package file_operation;

import time.Timewait;

import java.io.*;

public class FileCopy2 {
    private File sourcePath;    // 源路径
    private File targetPath;    // 目标路径
    private StringBuilder stringBuilder;
    private FileFilter filter;  // 过滤器

    public FileCopy2(String sourcePath, String targetPath) {
        this.sourcePath = new File(sourcePath);
        this.targetPath = new File(targetPath + "\\" + this.sourcePath.getName());
        stringBuilder = new StringBuilder(this.targetPath.getPath());
        filter = null;
    }

    public FileCopy2() {
        sourcePath = targetPath = null;
        stringBuilder = null;
        filter = null;
    }

    public void setFilter(FileFilter filter) {
        this.filter = filter;
    }

    public void setSourcePath(String sourcePath) {
        this.sourcePath = new File(sourcePath);
    }

    public void setTargetPath(String targetPath) {
        this.targetPath = new File(targetPath);
        stringBuilder = new StringBuilder(this.targetPath.getPath());
    }

    /** 开始复制 */
    public boolean startCopy() {
        if (!sourcePath.exists()) {
            System.out.println("源路径不存在！");
            return false;
        }
        File[] files = sourcePath.isFile() ? new File[]{sourcePath} :
                filter != null ? sourcePath.listFiles(filter) : sourcePath.listFiles();
        assert files != null;
        if (filter != null)
            traverseCopyFilter(files);
        else
            traverseCopy(files);
        return true;
    }

    /** 遍历目录下的文件及目录并复制 */
    private void traverseCopy(File[] files) {
        for (File file : files) {
//            System.out.println(file);
            if (file.isFile())
                copy(file, new File(targetPath.getPath() +
                        file.getPath().substring(sourcePath.getPath().length())));
            else
            {
                new File(targetPath.getPath() +
                        file.getPath().substring(sourcePath.getPath().length())).mkdirs();
                traverseCopy(file.listFiles());
            }
        }
    }
    /** 遍历目录下的文件及目录并复制（根据过滤器进行过滤） */
    private void traverseCopyFilter(File[] files) {
        for (File file : files) {
            if (file.isFile())
                copy(file, new File(targetPath.getPath() +
                        file.getPath().substring(sourcePath.getPath().length())));
            else
            {
                new File(targetPath.getPath() +
                        file.getPath().substring(sourcePath.getPath().length())).mkdirs();
//                File[] files1 = filter != null ? file.listFiles(filter) : file.listFiles();
//                File[] files1;
//                if (filter != null)
//                    files1 = file.listFiles(filter);
//                else
//                    files1 = file.listFiles();
//                traverseCopy(files1);
                traverseCopyFilter(file.listFiles(filter));
            }
        }
    }

    private void traverseCopy2(File[] files) {
        for (File file : files) {
            if (file.isFile()) {
                stringBuilder.append(file.getPath().substring(sourcePath.getPath().length()));
                copy(file, new File(stringBuilder.toString()));
                stringBuilder.delete(targetPath.getPath().length(), stringBuilder.length());
            }
            else {
                int end = file.getPath().length();
                stringBuilder.append(file.getPath(), sourcePath.getPath().length(), end);
                File path = new File(stringBuilder.toString());
                if (!path.exists())
                    path.mkdirs();
                stringBuilder.delete(targetPath.getPath().length(), stringBuilder.length());
                traverseCopy2(file.listFiles());
            }
        }
    }

    /** 复制文件 */
    private void copy(File sourceFile, File targetFile) {
        File parent = targetFile.getParentFile();
        if (!parent.exists())
            parent.mkdirs();
        try(FileInputStream fis = new FileInputStream(sourceFile);
            FileOutputStream fos = new FileOutputStream(targetFile)) {
            byte[] buffer = new byte[1024 * 10];
            /**
             * 1024 * 10
             * 10240
             * 这两种写法无性能损耗
             * java编译器在编译期会把只有直接量的计算表达式（能确定计算结果的表达式）计算结果之后再将结果替换原来的表达式
             * */
            int len;
            while ((len = fis.read(buffer)) != -1)
                fos.write(buffer, 0, len);
            fos.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        carry();
    }

    public static void carry() {
        String sourcePaths = "D:\\Projects\\JavaDemo";
//        String targetPath = "F:\\projects\\";
        String targetPath = "F:/projects/";
        if (targetPath.lastIndexOf("\\") == targetPath.length() - 1 ||
                targetPath.lastIndexOf("/") == targetPath.length() - 1)
            targetPath = targetPath.substring(0, targetPath.length() - 1);
        FileCopy2 fc = new FileCopy2(sourcePaths, targetPath);
//        fc.setFilter(file -> !(file.getName().equals(".git") || "out".equals(file.getName())));
        fc.setFilter(file -> !(".idea".equals(file.getName()) ||
                ".git".equals(file.getName()) || "out".equals(file.getName())));
        System.out.println("复制中......");
        String time = Timewait.timewait(fc::startCopy);     // 调用fc对象的startCopy()方法并计时
        System.out.println("复制完毕\n" + time);
    }

    public static void test() {
//        String[] sourcePaths = {"D:\\Projects\\JavaDemo\\img", "D:\\Projects\\JavaDemo\\src"};
//        String targetPath = "D:\\test\\JavaDemo";
        String[] sourcePaths = {"D:\\Projects\\jsd2208-se-teacher"};
        String targetPath = "D:\\Projects\\JavaMavenDemoT";
        if (targetPath.lastIndexOf("\\") == targetPath.length() - 1)
            targetPath = targetPath.substring(0, targetPath.lastIndexOf("\\"));
        FileCopy2 fc = new FileCopy2();
        fc.setFilter(file -> !(file.getName().equals(".idea") || file.getName().equals(".git")));
        System.out.println("复制中......");
        long startTime = System.currentTimeMillis();
        for (String sourcePath : sourcePaths) {
            fc.setSourcePath(sourcePath);
//            fc.setTargetPath(targetPath + "\\" + sourcePath.substring(sourcePath.lastIndexOf("\\")));
            fc.setTargetPath(targetPath);
            fc.startCopy();
        }
        long time = System.currentTimeMillis() - startTime;
        System.out.println("复制完毕\n耗时：" + time + "毫秒");
    }
}
